#include <stdio.h>


// int main()
// {
//     const char* p = "abcdef";
//     return 0;
// }




// //函数指针的理解
// typedef void(* pf_t)(int);//把void(*)(int)这个函数指针类型重命名为pf_t
// int main()
// {
//     void(* signal(int,void(*)(int)))(int);
//     //上一行代码与下一行经typedef重命名后的形式等价
    
//     pf_t signal1(int,pf_t);

// }




// //函数指针的应用实例，这种写法也成为函数回调
// //计算器的实现
// int add(int x,int y)
// {
//     return x + y;
// }
// int sub(int x,int y)
// {
//     return x - y;
// }
// int mul(int x,int y)
// {
//     return x * y;
// }
// int div(int x,int y)
// {
//     return x / y;
// }
// void cal(int (*pf)(int x,int y))//函数指针可以减少冗余代码
// {
//     int x = 0;
//     int y = 0;
//     printf("请输入两个整数\n");
//     scanf("%d %d",&x,&y);
//     int ret = pf(x,y);
//     printf("结果为%d\n",ret);
// }
// void menu()
// {
//     printf("*****************************\n");
//     printf("*****  1. add    2.sub  *****\n");
//     printf("*****  3. mul    4.div  *****\n");
//     printf("*****       0.exit      *****\n");
//     printf("*****************************\n");
// }
// int main()
// {
//     int input = 0;
//     do
//     {
//         menu();
//         printf("请输入要选择的功能\n");
//         scanf("%d",&input);
//         switch(input)
//         {
//         case 1:
//             cal(add);
//             break;
//         case 2:
//             cal(sub);
//             break;
//         case 3:
//             cal(mul);
//             break;
//         case 4:
//             cal(div);
//             break;
//         case 0:
//             printf("退出\n");
//             break;
//         default:
//             printf("输入错误，请重新输入\n");
//             break;
//         }
//     } while (input);
//     return 0;
// }



// //改为用函数指针数组的形式来实现
// int add(int x,int y)
// {
//     return x + y;
// }
// int sub(int x,int y)
// {
//     return x - y;
// }
// int mul(int x,int y)
// {
//     return x * y;
// }
// int div(int x,int y)
// {
//     return x / y;
// }
// void menu()
// {
//     printf("*****************************\n");
//     printf("*****  1. add    2.sub  *****\n");
//     printf("*****  3. mul    4.div  *****\n");
//     printf("*****       0.exit      *****\n");
//     printf("*****************************\n");
// }
// int main()
// {
//     int input = 0;
//     int x = 0;
//     int y = 0;
//     int ret = 0;
//     do
//     {
//         menu();
//         printf("请输入要选择的功能\n");
//         scanf("%d",&input);
//         //定义函数指针数组，巧妙的加入数字0，使得数字正好与函数功能对应
//         int (*pfarr[5])(int,int) = {0,add,sub,mul,div};
//         if(input == 0)
//         {
//             printf("退出\n");
//         }
//         else if(input >= 1 && input <= 4)
//         {
//             printf("请输入两个整数\n");
//             scanf("%d %d",&x,&y);
//             ret = pfarr[input](x,y);
//             printf("结果为%d\n",ret);
//         }
//         else
//         {
//             printf("输入错误，请重新输入\n");
//         }
//     } while (input);
//     return 0;
// }





// //冒泡排序
// void bubble_sort(int* arr,int sz)
// {
//     int i = 0;
//     int flag = 1;
//     for(i = 0;i < sz; i++)
//     {
//         //第i趟排序
//         int j = 0;
//         for(j = 0; j < sz - 1 - i;j++)//每趟排序次数减少一次
//         {
//             if(arr[j] > arr[j+1])
//             {
//                 int temp = arr[j];
//                 arr[j] = arr[j+1];
//                 arr[j+1] = temp;
//                 flag = 0;
//             }
//         }
//         if(flag == 1)//如果有一轮一次都没交换，说明已有序
//         {
//             break;
//         }
//     }
// }
// int main()
// {
//     int arr[] = {10,9,8,7,6,5,4,3,2,1};
//     int sz = sizeof(arr) / sizeof(arr[0]);
//     bubble_sort(arr,sz);
//     int i = 0;
//     for(i = 0;i < sz;i++)
//     {
//         printf("%d ",arr[i]);
//     } 
//     return 0;
// }


//用sort来实现排序体会回调函数的用途
//qsort可以排序任意类型的数据
// void qsort( void *base, //待排序数据的起始位置
//             size_t num, //待排序数据的个数
//             size_t width, //待排序数据元素的大小
//             int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
//             //函数指针，比较函数
//             //__cdecl 是c里的函数调用约定
// 比较函数返回值的要求 Return Value Description 
// < 0        elem1 less than elem2 
// 0          elem1 equivalent to elem2 
// > 0        elem1 greater than elem2 

// #include <stdlib.h>
// int cmp_int(const void *e1, const void *e2)
// {
//     //void*代表无具体类型的指针，可以接受任何类型的指针
//     //正因如此无法直接解引用，需要先强制类型转换
//     return(*(int*)e1 - *(int*)e2);
// }
// int main()
// {
//     int arr[] = {10,9,8,7,6,5,4,3,2,1};
//     int sz = sizeof(arr) / sizeof(arr[0]);
//     qsort(arr,sz,sizeof(arr[0]),cmp_int);
//     int i = 0;
//     for(i = 0;i < sz;i++)
//     {
//         printf("%d ",arr[i]);
//     } 
//     return 0;
// }





// //使用qsort来实现结构体的排序
// #include <stdlib.h>
// #include <string.h>
// struct stu
// {
//     char name[20];
//     int age;
// };
// int cmp_by_name(const void* e1,const void* e2)
// {
//     //strcmp的返回值正好与cmp要求的值相同
//     return strcmp(((struct stu*)e1)->name,((struct stu*)e2)->name);
// }
// int cmp_by_age(const void* e1,const void* e2)
// {
//     return(((struct stu*)e1)->age-((struct stu*)e2)->age);
// }
// int main()
// {
//     struct stu s[] = {{"zhangsan",15},{"lisi",30},{"wangwu",25}};
//     int sz = sizeof(s) /sizeof(s[0]);
//     qsort(s,sz,sizeof(s[0]),cmp_by_name);
//     qsort(s,sz,sizeof(s[0]),cmp_by_age);
//     return 0;
// }





// //将冒泡排序改造成类似于qsort函数的形式

// void universal_swap(char* buf1,char* buf2,int width)
// //被调用函数要放在前面，不然编译器识别不到
// {
//     int i = 0;
//     for(i = 0;i < width;i++)//因为不知道几个字节，所以逐字节互换
//     {
//         char temp = *buf1;
//         *buf1 = *buf2;
//         *buf2 = temp;
//         //下面两句不能忘
//         buf1++;
//         buf2++;
//     }
// }
// int bubble_sort(void* base,int sz,int width,int (*cmp)(const void* e1,const void* e2))
// {
//     int i = 0;
//     int flag = 1;
//     for(i = 0;i < sz; i++)
//     {
//         int j = 0;
//         for(j = 0; j < sz - 1 - i;j++)
//         {
//             //因为不知道要比较的元素类型，所以直接用最小的char（一个字节）
//             if(cmp((char*)base+j*width,(char*)base+(j+1)*width) > 0)
//             {
//                 universal_swap((char*)base+j*width,(char*)base+(j+1)*width,width);
//                 flag = 0;
//             }
//         }
//         if(flag == 1)
//         {
//             break;
//         }
//     }
// }
// int cmp_int(const void* e1,const void* e2)
// {
//     return(*(int*)e1-*(int*)e2);
// }
// int main()
// {
//     int arr[] = {10,9,8,7,6,5,4,3,2,1};
//     int sz = sizeof(arr) / sizeof(arr[0]);
//     bubble_sort(arr,sz,sizeof(arr[0]),cmp_int);
//     int i = 0;
//     for(i = 0;i < sz;i++)
//     {
//         printf("%d ",arr[i]);
//     } 
//     return 0;
// }


//用写出来的新冒泡排序来对结构体排序
#include <string.h>
struct stu
{
    char name[20];
    int age;
};
void universal_swap(char* buf1,char* buf2,int width)

{
    int i = 0;
    for(i = 0;i < width;i++)
    {
        char temp = *buf1;
        *buf1 = *buf2;
        *buf2 = temp;
        buf1++;
        buf2++;
    }
}
int bubble_sort(void* base,int sz,int width,int (*cmp)(const void* e1,const void* e2))
{
    int i = 0;
    int flag = 1;
    for(i = 0;i < sz; i++)
    {
        int j = 0;
        for(j = 0; j < sz - 1 - i;j++)
        {
            if(cmp((char*)base+j*width,(char*)base+(j+1)*width) > 0)
            {
                universal_swap((char*)base+j*width,(char*)base+(j+1)*width,width);
                flag = 0;
            }
        }
        if(flag == 1)
        {
            break;
        }
    }
}
int cmp_by_name(const void* e1,const void* e2)
{
    return strcmp(((struct stu*)e1)->name,((struct stu*)e2)->name);
}
int cmp_by_age(const void* e1,const void* e2)
{
    return(((struct stu*)e1)->age-((struct stu*)e2)->age);
}
int main()
{
    struct stu s[] = {{"zhangsan",15},{"lisi",30},{"wangwu",25}};
    int sz = sizeof(s) /sizeof(s[0]);
    bubble_sort(s,sz,sizeof(s[0]),cmp_by_name);
    bubble_sort(s,sz,sizeof(s[0]),cmp_by_age);
    //调试在监视中查看
    return 0;
}